#include "common.h"
#include "dpdk.h"
#include "arp.h"
#include "udp.h"
#include "tcp.h"
#include "icmp.h"

#if ENABLE_KNI
#include "m_kni.h"
#endif

int pkt_process(void * arg){  // 从 in ring 中 不断拿出数据包 分发不同协议数据包处理
    struct rte_mempool * m_pool = (struct rte_mempool *)arg;
    struct inout_ring * ring = ring_instance();
    while(1){
        struct rte_mbuf * mbufs[BURST_SIZE];
        unsigned num_recved = rte_ring_mc_dequeue_burst(ring->in, (void **)mbufs, BURST_SIZE, NULL);
//        printf("-----------------e------%d-------------->>  \n", num_recved);
        unsigned i = 0;
        for(i = 0; i < num_recved; i++){
            struct rte_ether_hdr * ehdr = rte_pktmbuf_mtod(mbufs[i], struct rte_ether_hdr *);
            if(ehdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)){
                arp_process(mbufs[i], ring, g_mpool);
                continue;
            }
            if (ehdr->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
#if ENABLE_KNI
                struct rte_kni
                rte_kni_tx_burst(global_kni, mbufs, num_recved);
#else                              
                continue;
#endif                 
            }
            struct rte_ipv4_hdr * iphdr = rte_pktmbuf_mtod_offset(mbufs[i], struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
            if(iphdr->next_proto_id == IPPROTO_UDP){
                udp_process(mbufs[i]);
//                udp_pkt_process(mbufs[i], g_mpool);
            } else if(iphdr->next_proto_id == IPPROTO_TCP){
                tcp_process(mbufs[i]);
            } else if(iphdr->next_proto_id == IPPROTO_ICMP){
                icmp_echo_request(mbufs[i], ring, g_mpool);
            } else{
#if ENABLE_KNI
                rte_kni_tx_burst(global_kni, mbufs, num_recved);
#endif                
            }
        }
        udp_out(m_pool);
        tcp_out(m_pool);

#if ENABLE_KNI
        rte_kni_handle_request(global_kni);
#endif

    }
    return 0;
}


int main(int argc, char * argv[]){
    dpdk_init(argc, argv, &g_mpool);


#if ENABLE_KNI
    alloc_kni(g_mpool, &global_kni);
#endif
    

    rte_eth_macaddr_get(0, (struct rte_ether_addr *)g_src_mac);
    rte_timer_subsystem_init();
    struct rte_timer arp_timer;
    uint64_t hz = rte_get_timer_hz();
    unsigned l_core_id = rte_lcore_id();
    rte_timer_reset(&arp_timer, hz, PERIODICAL, l_core_id, arp_request_timer_cb, g_mpool);
    struct inout_ring * ring = ring_instance();
    if(ring == NULL){
        rte_exit(EXIT_FAILURE, "----> ring_instance ");
    }

    if(ring->in == NULL){
        ring->in = rte_ring_create("in ring", RING_SIZE, rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);
    }
    if(ring->out == NULL){
        ring->out = rte_ring_create("out ring", RING_SIZE, rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);
    }

    // 接收网络包 解析 网络包
    l_core_id = rte_get_next_lcore(l_core_id, 1, 0);
    rte_eal_remote_launch(pkt_process, g_mpool, l_core_id);
    // UDP server
    l_core_id = rte_get_next_lcore(l_core_id, 1, 0);
    rte_eal_remote_launch(udp_server_entry, g_mpool, l_core_id);
    // TCP server
    l_core_id = rte_get_next_lcore(l_core_id, 1, 0);
    rte_eal_remote_launch(tcp_server_entry, g_mpool, l_core_id);

    while(1){ // 发送和接收网卡消息
        struct rte_mbuf * rx_buf[BURST_SIZE];
        unsigned  num_recved = rte_eth_rx_burst(0, 0, rx_buf, BURST_SIZE);
        if(num_recved > BURST_SIZE){
            rte_exit(EXIT_FAILURE, "----> num_recved > BURST_SIZE ");
        } else if(num_recved > 0){
            rte_ring_sp_enqueue_burst(ring->in, (void **)rx_buf, num_recved, NULL);
        }

        struct rte_mbuf * tx_buf[BURST_SIZE];
        unsigned num_tx = rte_ring_sc_dequeue_burst(ring->out, (void **)tx_buf, BURST_SIZE, NULL);
        if(num_tx > 0){
            rte_eth_tx_burst(0, 0, tx_buf, num_tx);
            unsigned i = 0;
            for(; i < num_tx; i++){
                rte_pktmbuf_free(tx_buf[i]);
            }
        }

        static uint64_t  prev_tsc = 0, cur_tsc;
        uint64_t diff_tsc;
        cur_tsc = rte_rdtsc();
        diff_tsc = cur_tsc - prev_tsc;
        if(diff_tsc > TIMER_RESOLUTION_CYCLES){
            rte_timer_manage();
            prev_tsc = cur_tsc;
        }
    }
    return 0;
}